package com.liuwei.spring.cloud.configuration;

import com.liuwei.spring.cloud.framework.constants.RedisCache;
import com.liuwei.spring.cloud.framework.spring.ApplicationHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author : evan.liu
 * @version V1.0
 * @Description: TODO
 * @date Date : 2022年07月02日 10:59 下午
 */
@Slf4j
@Configuration
@EnableCaching
public class RedisConfiguration {

    @Primary
    @Bean(RedisCache.CACHE_MANAGER)
    public CacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {
        String cachePrefix = ApplicationHelper.getApplicationName();
        //初始化一个RedisCacheWriter输出流
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
        //采用 Jackson2JsonRedisSerializer序列化机制
        RedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
        //创建一个RedisSerializationContext.SerializationPair给定的适配器pair
        // SerializationPair used for de-/serializing cache keys/values
        RedisSerializationContext.SerializationPair<String> keyPair = RedisSerializationContext.SerializationPair.fromSerializer(serializer);
        RedisSerializationContext.SerializationPair<Object> valuePair = RedisSerializationContext.SerializationPair.fromSerializer(serializer);

        //创建 DefaultCacheConfig
        RedisCacheConfiguration defaultCache = RedisCacheConfiguration
                .defaultCacheConfig()
                .serializeValuesWith(valuePair);
        defaultCache = defaultCache.entryTtl(Duration.ofMinutes(10));

        // 自定义Cache
        Map<String, RedisCacheConfiguration> initialCacheConfigurations = new HashMap<>(16);
        if(ArrayUtils.isNotEmpty(RedisCache.CacheProperty.values())){
            for (RedisCache.CacheProperty config: RedisCache.CacheProperty.values()){
                RedisCacheConfiguration custom = RedisCacheConfiguration
                        .defaultCacheConfig()
                        .serializeValuesWith(valuePair);
                Duration duration = null;
                // 如果过期时间小于 0; 则默认不过期
                if(config.getTtl()<0){
                    initialCacheConfigurations.put(config.name(),custom);
                    continue;
                }
                // 如果过期时间大于等于0; 设置对应的过期时间
                if(TimeUnit.NANOSECONDS.equals(config.getUnit())){
                    duration = Duration.ofNanos(config.getTtl());
                }
                if(TimeUnit.MICROSECONDS.equals(config.getUnit())){
                    duration = Duration.ofNanos(config.getTtl()*1000);
                }
                if(TimeUnit.MILLISECONDS.equals(config.getUnit())){
                    duration = Duration.ofMillis(config.getTtl());
                }
                if(TimeUnit.SECONDS.equals(config.getUnit())){
                    duration = Duration.ofSeconds(config.getTtl());
                }
                if(TimeUnit.MINUTES.equals(config.getUnit())){
                    duration = Duration.ofMinutes(config.getTtl());
                }
                if(TimeUnit.HOURS.equals(config.getUnit())){
                    duration = Duration.ofHours(config.getTtl());
                }
                if(TimeUnit.DAYS.equals(config.getUnit())){
                    duration = Duration.ofDays(config.getTtl());
                }
                custom = custom.entryTtl(duration);
                log.info("cacheName:{}",config.name());
                initialCacheConfigurations.put(config.name(),custom);
            }
        }
        RedisCacheManager manager = new RedisCacheManager(redisCacheWriter, defaultCache,initialCacheConfigurations);
        return manager;
    }
}
